<?php
/**
 * Created by PhpStorm.
 * User: 96572
 * Date: 2017/4/29
 * Time: 15:28
 */

namespace app\modules\admin\models;

use app\common\CommonController;
use Yii;
use yii\db\ActiveRecord;
use yii\helpers\Url;
use yii\helpers\VarDumper;

/**
 * This is the model class for table "{{%user}}".
 *
 * @property integer $menu_id
 * @property string $menu_label
 * @property string $menu_icon
 * @property string $menu_module_id
 * @property string $menu_controller_id
 * @property string $menu_action_id
 * @property integer $menu_is_visible
 * @property integer $menu_parent_id
 * @property integer $menu_is_lowest
 */
class Menu extends ActiveRecord
{
    const SCENARIO_IS_LOWEST_INSERT = 'is_lowest_insert';
    const SCENARIO_NOT_LOWEST_INSERT = 'not_lowest_insert';
    const SCENARIO_IS_LOWEST_UPDATE = 'is_lowest_update';
    const SCENARIO_NOT_LOWEST_UPDATE = 'not_lowest_update';
    // 是否为拥有最下级分类
    public function attributeLabels()
    {
        return [
            'menu_id'  =>'菜单id',
            'menu_label'   =>'菜单名称',
            'menu_icon'=> '菜单图标',
            'menu_module_id'   =>'模块id',
            'menu_controller_id'   =>'控制器id',
            'menu_action_id'   =>'动作id',
            'menu_is_visible'  =>'是否可见',
            'menu_parent_id'   =>'父菜单id',
            'menu_is_lowest'   =>'是否是最下级菜单',
        ];
    }
    public function scenarios()
    {
        $attributes[static::SCENARIO_IS_LOWEST_INSERT] = [
            'menu_id','menu_label','menu_icon','menu_module_id','menu_controller_id','menu_action_id','menu_is_visible','menu_parent_id','menu_is_lowest'
        ];
        $attributes[static::SCENARIO_NOT_LOWEST_INSERT] = [
            'menu_id','menu_label','menu_icon','menu_is_visible','menu_parent_id'
        ];
        $attributes[static::SCENARIO_IS_LOWEST_UPDATE] = [
            'menu_id','menu_label','menu_icon','menu_module_id','menu_controller_id','menu_action_id','menu_is_visible','menu_parent_id'
        ];
        $attributes[static::SCENARIO_NOT_LOWEST_UPDATE] = [
            'menu_id','menu_label','menu_icon','menu_is_visible','menu_parent_id'
        ];
        return $attributes;
    }

    public function rules()
    {
        return [
            [
                ['menu_label','menu_is_visible','menu_parent_id','menu_is_lowest'],
                'required',
                'message'=>'不能为空'
            ],
            [
                'menu_icon','default','value'=>''// 这个配置项没用
            ],
            ['menu_label','string','max'=>10],
            ['menu_icon','string','max'=>20],
            [
                ['menu_is_visible','menu_parent_id','menu_is_lowest'],
                'integer'
            ],
            [
                ['menu_is_visible','menu_is_lowest'],
                'in',
                'range'=>[0,1]
            ],
            [
                ['menu_module_id', 'menu_controller_id', 'menu_action_id'],
                'required',
                'on' => static::SCENARIO_IS_LOWEST_INSERT
            ],
            [
                ['menu_module_id', 'menu_controller_id', 'menu_action_id'],
                'validateActionID',
                'on' => static::SCENARIO_IS_LOWEST_INSERT
            ],
            ['module_id','validateModuleID'],
            ['controller_id','validateControllerID'],
            ['action_id','validateActionID'],
        ];
    }

    /**
     * 验证模块是否存在
     * @return bool
     */
    public function validateModuleID()
    {
        if(!\Yii::$app->hasModule($this->menu_module_id))
        {
            $this->addError(
                'menu_module_id',
                \Yii::t('blog','RBAC_MODULE_NOT_EXIST')
            );
            return false;
        }
        return true;
    }

    /**
     * 验证控制器是否存在
     * @return bool
     */
    public function validateControllerID()
    {
        if(false === $this->validateModuleID())
        {
            return false;
        }

        $module = \Yii::$app->getModule($this->menu_module_id);
        $controller = $module->createControllerByID($this->menu_controller_id);
        if(!$controller)
        {
            $this->addError(
                'menu_controller_id',
                \Yii::t('blog','RBAC_CONTROLLER_NOT_EXIST')
            );
            return false;
        }
        return true;
    }

    public function validateActionID ()
    {
        if (false === $this->validateControllerID())
        {
            return false;
        }

        $module = \Yii::$app->getModule($this->menu_module_id);
        $controller = $module->createControllerByID($this->menu_controller_id);
        if (is_null($controller->createAction($this->menu_action_id))) {
            $this->addError('menu_action_id',Yii::t('blog','RBAC_ACTION_NOT_EXIST'));
            return false;
        }

        $exist = static::find()->where([
            'menu_module_id'  =>    $this->menu_module_id,
            'menu_controller_id'  =>    $this->menu_controller_id,
            'menu_action_id'  =>    $this->menu_action_id,
        ])->exists();
        if ($exist)
        {
            $this->addError('menu_module_id',Yii::t('blog','MENU_EXISTS'));
            return false;
        }

        return !$exist;
    }

    public function save($runValidation = true, $attributeNames = null)
    {
        // 开始事务
        $transition = static::getDb()->beginTransaction();
        try
        {
            if(false === parent::save($runValidation, $this->attributes()))
            {
                throw new \Exception();
            }
            $auth = Yii::$app->authManager;
            $name = CommonController::getPermissionNameByRoute(
                $this->menu_module_id,
                $this->menu_controller_id,
                $this->menu_action_id
            );
            // 是否是最下级分类，创建最下级分类时需要添加权限
            if ($this->scenario == static::SCENARIO_IS_LOWEST_INSERT) {

                $permission = $auth->getPermission($name);
                if (!$permission) {
                    $createPost = $auth->createPermission($name);
                    $createPost->description = $this->menu_label;
                    $auth->add($createPost);
                } else {
                    $permission->description = $this->menu_label;
                    $permission->name = $name;
                    $auth->update($name,$permission);
                }
            } elseif ($this->scenario == static::SCENARIO_IS_LOWEST_UPDATE) {

                $oldName = CommonController::getPermissionNameByRoute(
                    $this->oldAttributes['menu_module_id'],
                    $this->oldAttributes['menu_controller_id'],
                    $this->oldAttributes['menu_action_id']
                );
                $permission = $auth->getPermission($oldName);
                if (!$permission)
                {
                    $createPost = $auth->createPermission($name);
                    $createPost->description = $this->menu_label;
                    $auth->add($createPost);
                }
                else
                {
                    $permission->description = $this->menu_label;
                    $permission->name = $name;
                    $auth->update($oldName,$permission);
                }
            }
            $transition->commit();
            return true;
        }
        catch (\Exception $e)
        {
            if ($e->getMessage())
            {
                $this->addError('menu_name',$e->getMessage());
            }
            $transition->rollBack();
            return false;
        }
    }

    /**
     * 获得在前台显示的菜单
     */
    public static function getVisibleMenu()
    {
        $menus = static::find()->where(['menu_is_visible'=>1])->asArray()->all();
        return $menus;
    }

    /**
     * 获得在前台显示的菜单
     */
    public static function getMenu()
    {
        $menus = static::find()->asArray()->all();
        return $menus;
    }

    /**
     * 获得在前台显示的菜单
     */
    public static function getMenuTree()
    {
        $menus = static::getMenu();
        $menus = static::toTree($menus);
        return $menus;
    }

    /**
     * 获得在前台显示的菜单
     */
    public static function getVisibleMenuTree()
    {
        $menus = static::getVisibleMenu();
        $menus = static::toTree($menus);
        return $menus;
    }

    /**
     * 把菜单转换成树形结构，在后台展示
     * @param array $menus
     * @param int $parentMenuID
     * @return array
     */
    public static function toTree($menus,$parentMenuID = 0)
    {
        $menuArray = [];
        foreach ($menus as $index => $menu) {
            if ($menu['menu_parent_id'] == $parentMenuID)
            {
                $menu['has_lowest_menu'] = false;
                if ($menu['menu_is_lowest'])
                {
                    $menu['has_lowest_menu'] = true;
                }
                else
                {
                    $menu['children'] = static::toTree($menus,$menu['menu_id']);
                    foreach ($menu['children'] as $child) {
                        if ($child['menu_is_lowest'] == 1)
                        {
                            $menu['has_lowest_menu'] = true;
                            break;
                        }
                    }
                }
                $menuArray[] = $menu;
            }
        }
        return $menuArray;
    }
    /**
     * 获得在前台显示的菜单
     */
    public static function getMenuTreeForLeftMenu()
    {
        $menus = static::getMenu();
        $menus = static::toTreeForLeftMenu($menus);
        return $menus;
    }
    /**
     * 把菜单转换成树形结构，用于在左边栏展示
     * @param Menu[] $menus
     * @param int $parentMenuID
     * @return array
     */
    public static function toTreeForLeftMenu($menus,$parentMenuID = 0)
    {
        $menuArray = [];
        $url = null;
        foreach ($menus as $index => $menu) {
            if ($menu['menu_parent_id'] == $parentMenuID)
            {
                $menu['has_lowest_menu'] = false;
                if ($menu['menu_is_lowest'])
                {
                    $menu['has_lowest_menu'] = true;
                    $url = Url::toRoute(
                        '/' . $menu['menu_module_id'] . '/' .$menu['menu_controller_id'] . '/' . $menu['menu_action_id']
                    );
                    $menu['child_menu_id'] = [];
                }
                else
                {
                    $menu['items'] = static::toTreeForLeftMenu($menus,$menu['menu_id']);
                    $tempChildMenu = [];
                    foreach ($menu['items'] as $child) {
                        $tempChildMenu = array_merge(
                            $tempChildMenu,
                            [$child['menu_id']],
                            $child['child_menu_id']
                        );
                        if ($child['menu_is_lowest'] == 1)
                        {
                            $menu['has_lowest_menu'] = true;
                        }
                    }
                    $menu['child_menu_id'] = $tempChildMenu;
                    $url = '#';
                }
                $temp = [
                    'label' => $menu['menu_label'],
                    'icon'  => $menu['menu_icon'],
                    'url'   => $url,
                    'menu_is_lowest'   => $menu['menu_is_lowest'],
                    'has_lowest_menu'   => $menu['has_lowest_menu'],
                    'menu_id'   => $menu['menu_id'],
                    'child_menu_id'   => $menu['child_menu_id'],
                    'visible'   => $menu['menu_is_visible']
                ];
                if (isset($menu['items']))
                {
                    $temp['items'] = $menu['items'];
                }
                $menuArray[] = $temp;
            }
        }
        return $menuArray;
    }
}